package com.elysia.gatewayservice.filter;

import com.elysia.gatewayservice.properties.JwtProperties;
import com.elysia.gatewayservice.untils.JwtUtils;
import io.jsonwebtoken.Claims;
import io.jsonwebtoken.ExpiredJwtException;
import io.jsonwebtoken.MalformedJwtException;
import io.jsonwebtoken.SignatureException;
import lombok.Data;
import lombok.extern.slf4j.Slf4j;
import org.springframework.cloud.gateway.filter.GatewayFilter;
import org.springframework.cloud.gateway.filter.factory.AbstractGatewayFilterFactory;
import org.springframework.http.HttpCookie;
import org.springframework.http.HttpStatus;
import org.springframework.http.server.reactive.ServerHttpRequest;
import org.springframework.http.server.reactive.ServerHttpResponse;
import org.springframework.stereotype.Component;
import org.springframework.util.AntPathMatcher;
import org.springframework.web.server.ServerWebExchange;
import reactor.core.publisher.Mono;

import java.util.List;

/**
 * 管理用户登录JWT令牌验证过滤器
 */
@Component
@Slf4j
public class JwtTokenFilterFactory extends AbstractGatewayFilterFactory<JwtTokenFilterFactory.Config> {

    private final JwtProperties jwtProperties;
    private final AntPathMatcher pathMatcher = new AntPathMatcher();

    public JwtTokenFilterFactory(JwtProperties jwtProperties) {
        super(Config.class);
        this.jwtProperties = jwtProperties;
    }

    @Data
    public static class Config {
        private List<String> excludePaths;
    }

    @Override
    public GatewayFilter apply(Config config) {
        return (exchange, chain) -> {
            ServerHttpRequest request = exchange.getRequest();
            String path = request.getURI().getPath();
            if (isExcludePath(path, config.getExcludePaths())) {
                return chain.filter(exchange);
            }
            // 令牌验证逻辑
            String token = request.getCookies()
                    .getOrDefault(jwtProperties.getAdminTokenName(), List.of())
                    .stream().findFirst().map(HttpCookie::getValue).orElse(null);
            if (token == null || token.trim().isEmpty()) {
                return setUnauthorizedResponse(exchange, "令牌不存在");
            }

            try {
                Claims claims = JwtUtils.parseJWT(jwtProperties.getAdminSecretKey(), token);
                Long id = claims.get("id", Long.class);
                ServerHttpRequest mutatedRequest = request.mutate()
                        .header("X-seacross-id", id.toString())
                        .build();
                return chain.filter(exchange.mutate().request(mutatedRequest).build());
            } catch (ExpiredJwtException e) {
                return setUnauthorizedResponse(exchange, "令牌已过期");
            } catch (SignatureException e) {
                return setUnauthorizedResponse(exchange, "令牌签名错误");
            } catch (MalformedJwtException e) {
                return setUnauthorizedResponse(exchange, "令牌格式错误");
            } catch (Exception e) {
                return setUnauthorizedResponse(exchange, "令牌验证失败：" + e.getMessage());
            }
        };
    }

    private boolean isExcludePath(String currentPath, List<String> excludePaths) {
        if (excludePaths == null || excludePaths.isEmpty())
            return false;
        for (String excludePath : excludePaths) {
            if (pathMatcher.match(excludePath, currentPath))
                return true;
        }
        return false;
    }

    private Mono<Void> setUnauthorizedResponse(ServerWebExchange exchange, String message) {
        ServerHttpResponse response = exchange.getResponse();
        response.setStatusCode(HttpStatus.UNAUTHORIZED);
        response.getHeaders().add("Content-Type", "application/json;charset=UTF-8");
        String body = "{\"code\":401,\"message\":\"" + message + "\"}";
        return response.writeWith(Mono.just(response.bufferFactory().wrap(body.getBytes())));
    }

    @Override
    public String name() {
        return "jwtToken";
    }
}